#ifndef __MF1Card_C
#define __MF1Card_C

#include "MF1Card.h"

//寻卡:req_code:寻卡方式:0x52=寻感应区内所有符合14443A标准的卡;0x26=寻未进入休眠状态的卡;
//pTagType:获取到的M1卡类型数据:0x4400 = Mifare_UltraLight / 0x0400 = Mifare_One(S50) / 0x0200 = Mifare_One(S70) / 0x0800 = Mifare_Pro(X) / 0x4403 = Mifare_DESFire;返回: 成功返回MI_OK;
char PcdRequest(unsigned char req_code,unsigned char *pTagType){
		char status;  
	  //M1卡返回数据大小;
		unsigned int  unLen;  
	  //与M1通讯缓存
		unsigned char ucComMF522Buf[MAXRLEN];   
	  //密码验证标志位,通过密码验证后自动置1,此时清0;
		ClearBitMask(Status2Reg,0x08);  
	  //发送字节控制寄存器;不启动数据发送
		WriteRawRC(BitFramingReg,0x07);  
	  //数据通过天线发送控制:TX1、TX2输出信号调制到13.56MHz的能量载波信号
		SetBitMask(TxControlReg,0x03);  
		
		//通过天线发送寻卡命令:
		ucComMF522Buf[0] = req_code;
		status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); 
		if((status == MI_OK) && (unLen == 0x10)){ //M1卡返回2b数据    
				*pTagType = ucComMF522Buf[0];  
				*(pTagType+1) = ucComMF522Buf[1];    
		}else{
				status = MI_ERR;    
		}
		return status;	
}

//防冲撞:pSnr:存放获取的卡片序列号,4字节;返回:成功返回MI_OK
char PcdAnticoll(unsigned char *pSnr){
		char status;
		unsigned char i,snr_check=0;
		unsigned int unLen;//M1卡返回的数据长度;
		unsigned char ucComMF522Buf[MAXRLEN]; 
		ClearBitMask(Status2Reg,0x08); //0x08
		WriteRawRC(BitFramingReg,0x00); //0x0D
		ClearBitMask(CollReg,0x80); //0x0E
		ucComMF522Buf[0] = PICC_ANTICOLL1;  //向M1卡发送的数据:M1卡命令字-防冲撞1方式进行; // 0x93
		ucComMF522Buf[1] = 0x20; //向M1卡发送的数据2:
		status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
		if (status == MI_OK){ //获取到卡号数据:4byte;
				for(i=0; i<4; i++){   
						*(pSnr+i) =  ucComMF522Buf[i];
						snr_check ^= ucComMF522Buf[i]; //与0异或[异同=1,相同=0]; snr_check按位翻转；
				}
				if(snr_check != ucComMF522Buf[i]){ //卡号格式验证
						status = MI_ERR;    
				}
		}
		SetBitMask(CollReg, 0x80);
		return status;	
}

//选定卡片:与卡建立通讯连接；pSnr:输入卡片序列号,4字节;返回:成功返回MI_OK
char PcdSelect(unsigned char *pSnr){
		char status;
		unsigned char i;
		unsigned int unLen;
		unsigned char ucComMF522Buf[MAXRLEN]; 
		ucComMF522Buf[0]=PICC_ANTICOLL1;//向卡发送的数据:卡命令字;
		ucComMF522Buf[1]=0x70;
		ucComMF522Buf[6]=0;
	  //向卡发送的数据:卡序列号;
		for(i = 0; i < 4; i++){ 
				ucComMF522Buf[i+2] = *(pSnr+i);
				ucComMF522Buf[6] ^= *(pSnr+i); //按位翻转;
		}
		CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
		ClearBitMask(Status2Reg,0x08);
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
		if ((status == MI_OK) && (unLen == 0x18)){ //选卡成功:  
				status = MI_OK;  
		}else{
				status = MI_ERR;
		}
		return status;
}

//验证卡片密码获取某扇区访问权限：auth_mode:密码验证模式[0x60=验证A密钥 0x61=验证B密钥]; 
//addr：块地址=扇区号;pKey：密码[6字节];pSnr:卡片序列号,4字节;返回:成功返回MI_OK;
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr){
		char status;
		unsigned int  unLen;
		unsigned char i,ucComMF522Buf[MAXRLEN];
		ucComMF522Buf[0] = auth_mode;//向卡发送的数据:;
		ucComMF522Buf[1] = addr;
		for (i = 0; i < 6; i++){ //向卡发送的数据:卡片的密码;    
				ucComMF522Buf[i + 2] = *(pKey + i);   
		}
		// 这里是4字节；原代码=6，现在已经改过；
		// 向卡发送的数据:卡序列号,4字节;
		for (i = 0; i < 4; i++){ 
				ucComMF522Buf[i + 8] = *(pSnr + i);
		} 
		status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
		if((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08))){
				status = MI_ERR;
		}
		return status;
}


//读取M1卡一块数据[16字节]:addr:块地址[块编号]；pData：块数据保存变量,16字节;返回:成功返回MI_OK
char PcdRead(unsigned char addr,unsigned char *pData){
		unsigned char status;
		unsigned int  unLen;
		unsigned char i,ucComMF522Buf[MAXRLEN];
		ucComMF522Buf[0]=PICC_READ;//向卡发送的数据:读命令;
		ucComMF522Buf[1] = addr;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);//计算数据校验码:
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
		if((status == MI_OK) && (unLen == 0x90)){
				for (i=0; i<16; i++){ //读取16字节数据:
						*(pData+i) = ucComMF522Buf[i];
				}
		}
		else{
				status = MI_ERR;
		}
		return status;
}

//写数据到M1卡一块：addr:块地址=块ID；pData:写入的数据,16字节;返回:成功返回MI_OK
char PcdWrite(unsigned char addr,unsigned char *pData){
		unsigned char status;
		unsigned int  unLen;
		unsigned char i,ucComMF522Buf[MAXRLEN]; 
		ucComMF522Buf[0] = PICC_WRITE; //向卡发送的数据:写命令;
		ucComMF522Buf[1] = addr;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
		status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
		if((status != MI_OK)||(unLen!=4)||((ucComMF522Buf[0] & 0x0F) != 0x0A)){
				status = MI_ERR;   
		}
		if(status == MI_OK){ //向卡发送的数据:准备好被写的数据;
				for(i = 0; i < 16; i++){
						ucComMF522Buf[i]=*(pData+i);
				}
				CalulateCRC(ucComMF522Buf, 16, &ucComMF522Buf[16]);//计算得到CRC16检验码:
				status=PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, &unLen);
				if((status != MI_OK)||(unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){
						status = MI_ERR;
				}
		}
		return status;	
}

//扣款和充值:dd_mode：命令字:0xC0=扣款 / 0xC1=充值;addr钱包地址=块id; 
//// pValue：4字节增(减)值，低位在前；返回:成功返回MI_OK
char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue){    
		unsigned char status;
		unsigned int  unLen;
		unsigned char i,ucComMF522Buf[MAXRLEN];
		
		//第1次向卡发送的数据:扣款或是充值;
		ucComMF522Buf[0] = dd_mode; 
		ucComMF522Buf[1] = addr;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);//ucComMF522Buf元素2-3存放校验码;
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);  
		if((status!=MI_OK) || (unLen != 4) || ((ucComMF522Buf[0]&0x0F)!=0x0A)){    
				status = MI_ERR;
		}
		
		//第2次向卡发送的数据:金额数据4字节;此处是否有误:
		if(status==MI_OK){ 
				for(i=0;i<4;i++){
						ucComMF522Buf[i]=*(pValue+i);
				}
				CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);//生成校验码:
				unLen=0;
				status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
				if(status!=MI_ERR){
						status = MI_OK;
				}
		}  
		
		//第3次向卡发送的数据:钱包地址;
		if(status == MI_OK){ 
				ucComMF522Buf[0] = PICC_TRANSFER;
				ucComMF522Buf[1] = addr;
				CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
				status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); 
				if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[0] & 0x0F) != 0x0A)){					
						status = MI_ERR;
				}
		}
		return status;
}

//备份数据:sourceaddr:源地址=块id;goaladdr:目标地址;返回:成功返回MI_OK
char PcdBakValue(unsigned char sourceaddr,unsigned char goaladdr){
		unsigned char status;
		unsigned int  unLen;
		unsigned char ucComMF522Buf[MAXRLEN];
		ucComMF522Buf[0] = PICC_RESTORE; //向卡发送的数据:备份命令字;
		ucComMF522Buf[1] = sourceaddr; //向卡发送的数据:源地址;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); 
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
		if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[0] & 0x0F) != 0x0A)){
				status = MI_ERR;
		}
		if(status == MI_OK){
				ucComMF522Buf[0]=0;
				ucComMF522Buf[1]=0;
				ucComMF522Buf[2]=0;
				ucComMF522Buf[3]=0;
				CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
				status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);			  
				if(status != MI_ERR){
						status = MI_OK;
				}
		}
		if (status != MI_OK){
				return MI_ERR;
		}
		ucComMF522Buf[0] = PICC_TRANSFER; //向卡发送的数据:; 
		ucComMF522Buf[1] = goaladdr; //向卡发送的数据:目标地址-备份数据的地址;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
		if((status!=MI_OK)||(unLen!=4)||((ucComMF522Buf[0]&0x0F)!=0x0A)){ 
				status = MI_ERR;
		}
		return status;	
}

//命令卡片进入休眠状态:返回:成功返回MI_OK
//使放置在读卡区的IC卡进入休眠状态，不再重复读卡
char PcdHalt(void){
		unsigned char status = MI_OK;
		unsigned int  unLen;
		unsigned char ucComMF522Buf[MAXRLEN]; 
		ucComMF522Buf[0] = PICC_HALT; //向卡发送的数据:休眠指令;
		ucComMF522Buf[1] = 0;
		CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
		status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
		return status;	
}

//用读卡器IC计算CRC16检验码:
//// pIndata:输入数据;
//// len:pIndata长度;
//// pOutData:存放校验码;
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData){
		char i,n;
		ClearBitMask(DivIrqReg,0x04);
		WriteRawRC(CommandReg,PCD_IDLE);
		SetBitMask(FIFOLevelReg,0x80);
		for(i=0; i<len; i++){
				WriteRawRC(FIFODataReg, *(pIndata+i));
		}
		WriteRawRC(CommandReg, PCD_CALCCRC);
		i = 0xFF;
		do{
				n = ReadRawRC(DivIrqReg);
				i--;
		}while((i != 0) && !(n & 0x04));
		pOutData[0] = ReadRawRC(CRCResultRegL);
		pOutData[1] = ReadRawRC(CRCResultRegM);
	
}

//设置RC522工作方式
char M500PcdConfigISOType(unsigned char type){
		if(type == 'A'){   //ISO14443_A
				ClearBitMask(Status2Reg,0x08); // Status2Reg = 0x08
				WriteRawRC(ModeReg,0x3D);//3F  ModeReg = 0x11
				WriteRawRC(RxSelReg,0x86);//84 RxSelReg = 0x17
				WriteRawRC(RFCfgReg,0x7F);   //4  RFCfgReg = 0x26
				// TReloadVal = 'h6a =tmoLength(dec) 
				WriteRawRC(TReloadRegL,30);//tmoLength); TReloadRegL = 0x2D
				WriteRawRC(TReloadRegH,0); // TReloadRegH = 0x2C
				WriteRawRC(TModeReg,0x8D); // TModeReg = 0x2A
				WriteRawRC(TPrescalerReg,0x3E); // TPrescalerReg = 0x2B
				delaynus(1);  //延时1us
				PcdAntennaOn();
		}else{ 
				return MI_ERR; 
		}
		return MI_OK;
}

//复位RC522读卡器:返回:成功返回MI_OK
char PcdReset(void){  
	  CardSPI_RST_High(); 
		delaynus(1);  //延时1us
	  CardSPI_RST_Low();
		delaynus(1);  //延时1us
	  CardSPI_RST_High();
		delaynus(10);               
		WriteRawRC(CommandReg,PCD_RESETPHASE); //0x01,0x0F 
		delaynus(1); //延时1us
		//和Mifare卡通讯,CRC初始值0x6363
		WriteRawRC(ModeReg,0x3D); 
		WriteRawRC(TReloadRegL,30);
		WriteRawRC(TReloadRegH,0);
		WriteRawRC(TModeReg,0x8D);
		WriteRawRC(TPrescalerReg,0x3E);
		WriteRawRC(TxAutoReg,0x40);
		return MI_OK;
}


//SPI通讯读数据[MCU与读卡器通讯]：读RC632寄存器:Address:寄存器地址;返回:读出的值
unsigned char ReadRawRC(unsigned char Address){
	  unsigned char ucResult = 0;
		unsigned char ucAddr = ((Address << 1) & 0x7E) | 0x80; 
		RS522_NSS_0;	  
		CardSPI_SendRead_Byte(ucAddr);
	  ucResult = CardSPI_SendRead_Byte(0x00);	  
		RS522_NSS_1;		
		return ucResult;
}


//SPI通讯写数据[MCU与读卡器通讯]：写RC632寄存器:Address:寄存器地址;value:写入的值;
void WriteRawRC(unsigned char Address,unsigned char value){  
		unsigned char ucAddr = ((Address << 1) & 0x7E);
	  RS522_NSS_0;
		CardSPI_SendRead_Byte(ucAddr);
	  CardSPI_SendRead_Byte(value);
	  RS522_NSS_1;	
}

//设置RC522寄存器某位=1：mask指定哪些位=1;reg:读卡器IC的寄存器地址;mask:指定寄存器哪些位=1。
void SetBitMask(unsigned char reg,unsigned char mask){
		char tmp = 0x00;
		tmp = ReadRawRC(reg);
		WriteRawRC(reg,tmp | mask); 
}

//设置RC522寄存器某位=0：mask指定哪些位=0;reg:读卡器IC的寄存器地址;mask:指定寄存器哪些位=0。
void ClearBitMask(unsigned char reg,unsigned char mask){
		char tmp = 0x0;
		tmp = ReadRawRC(reg);
		WriteRawRC(reg, tmp & ~mask);    
} 

//通过天线发送数据或接受数据:通过RC522和ISO14443卡通讯
/////  Command:RC522命令字；
/////  pInData:通过RC522发送到卡片的数据;
/////  InLenByte:pInData的字节长度；
/////  pOutData:接收卡的返回数据；
/////  *pOutLenBit:返回数据的位长度；
char PcdComMF522(unsigned char Command,unsigned char *pInData, 
                 unsigned char InLenByte,unsigned char *pOutData,
                 unsigned int  *pOutLenBit){
		char status = MI_ERR;
		unsigned char irqEn=0x00;
		unsigned char waitFor = 0x00;
		unsigned char lastBits;
		unsigned char n;
		unsigned int i;
		switch (Command){
				case PCD_AUTHENT:
						irqEn   = 0x12; 
						waitFor = 0x10; 
						break;
				case PCD_TRANSCEIVE:
						irqEn   = 0x77; 
						waitFor = 0x30; 
						break;
				default:
						break;
		}   
		WriteRawRC(ComIEnReg,irqEn | 0x80);
		ClearBitMask(ComIrqReg,0x80);
		WriteRawRC(CommandReg,PCD_IDLE);
		SetBitMask(FIFOLevelReg,0x80);
		for(i=0;i<InLenByte;i++){
				WriteRawRC(FIFODataReg,pInData[i]);
		}
		WriteRawRC(CommandReg, Command);
		if (Command == PCD_TRANSCEIVE){
				SetBitMask(BitFramingReg,0x80);
		}
		i=600; //根据时钟频率调整，操作M1卡最大等待时间25ms;
		do{
				n = ReadRawRC(ComIrqReg); 
				i--;
		} while((i!=0) && !(n & 0x01) && !(n & waitFor));
		ClearBitMask(BitFramingReg, 0x80);	      
		if(i!=0){    
				if(!(ReadRawRC(ErrorReg) & 0x1B)){
						status = MI_OK;
						if(n & irqEn & 0x01){
							status = MI_NOTAGERR;
						}
						if(Command == PCD_TRANSCEIVE){
								n = ReadRawRC(FIFOLevelReg);
								lastBits = ReadRawRC(ControlReg) & 0x07;
								if(lastBits){
										*pOutLenBit = (n-1) * 8 + lastBits;
								}else{
										*pOutLenBit = n * 8;
								}
								if(n==0){
										n = 1;
								}
								if(n > MAXRLEN){
										n = MAXRLEN;
								}
								for(i=0;i<n;i++){
										pOutData[i] = ReadRawRC(FIFODataReg);
								}
						}
				}else{
						status = MI_ERR;
				}
		}
		SetBitMask(ControlReg,0x80); // stop timer now
		WriteRawRC(CommandReg,PCD_IDLE); 
		return status;
}

//开启天线:每次启动或关闭天险发射之间应至少有1ms的间隔
void PcdAntennaOn(){
		unsigned char i; 
		i=ReadRawRC(TxControlReg);
		if(!(i & 0x03)){
				SetBitMask(TxControlReg,0x03);
		}  
}

//关闭天线：
void PcdAntennaOff(){
		ClearBitMask(TxControlReg,0x03);  
}

#endif

